package grouter

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
)

// node 路由树节点
type node struct {
	// 静态路由
	children map[string]*node
	// 正则路由-只能有一个
	regChild *node
	// 路径参数路由
	pathChild *node
	// 通配符路由
	wildChild *node
	// 执行逻辑
	handler HandleFunc
	// 正则匹配
	reg *regexp.Regexp
	// 路径参数名称
	pathName string
	// 保存path
	path string
}

type GCtx struct {
	Request *http.Request
	Params  map[string]string
	writer  http.ResponseWriter
}

func (this *GCtx) WriteString(s string) {
	this.writer.Write([]byte(s))
}

type HandleFunc func(ctx *GCtx)

// addRouter 添加路由
func (n *node) addRouter(path string, handler HandleFunc) {
	// 不支持以/结尾的路由 处分是根路径
	if len(path) > 1 && path[len(path)-1] == '/' {
		panic("path not support end with /")
	}

	// 处理后缀/
	path = strings.TrimSuffix(path, "/")

	if n.children == nil {
		n.children = make(map[string]*node)
	}

	child, ok := n.children[""]

	if !ok {
		child = &node{}
		n.children[""] = child
	}

	// 分割路径
	paths := splitPath(path)

	// 根节点
	if path == "" {
		child.handler = handler
	}

	// 递归添加路由
	child.addRouterRecursion(paths[1:], handler)
}

// addRouterRecursion 递归添加路由
func (n *node) addRouterRecursion(paths []string, handler HandleFunc) {
	// 路径为空
	if len(paths) == 0 {
		return
	}

	// 获取第一个路径
	path := paths[0]

	// 不支持空路径
	if path == "" {
		panic("path not support empty")
	}

	// n.path = path
	// 判断路由类型
	switch path[0] {
	case '(': // 正则路由
		// 校验是否已存在其它类型的路由
		if n.children != nil || n.pathChild != nil || n.wildChild != nil {
			panic("path not support mix regular route")
		}

		if n.regChild == nil {
			n.regChild = &node{path: path}
			// 正则校验
			reg, err := regexp.Compile(path)
			if err != nil {
				panic("reg compile error:" + path)
			}

			// 如果是最后一个
			if len(paths) == 1 {
				n.regChild.handler = handler
			}

			n.reg = reg
		} else {
			panic("reg router already exist")
		}

		n.regChild.addRouterRecursion(paths[1:], handler)
	case ':': // 路径参数
		// 校验是否已存在其它类型的路由
		if n.children != nil || n.regChild != nil || n.wildChild != nil {
			panic("path not support mix path route")
		}

		if n.pathChild == nil {
			n.pathChild = &node{path: path}
			n.pathName = path[1:]
		} else { // 不允许重复注册
			panic("path router already exist")
		}

		// 如果是最后一个
		if len(paths) == 1 {
			n.pathChild.handler = handler
		}

		n.pathChild.addRouterRecursion(paths[1:], handler)
	case '*': // 通配符
		// 校验是否已存在其它类型的路由
		if n.children != nil || n.regChild != nil || n.pathChild != nil {
			panic("path not support mix wild route")
		}

		if n.wildChild == nil {
			n.wildChild = &node{path: path}
		}

		// 如果是最后一个
		if len(paths) == 1 {
			n.wildChild.handler = handler
		}

		n.wildChild.addRouterRecursion(paths[1:], handler)
	default: // 静态路由
		// 校验是否已存在其它类型的路由
		if n.regChild != nil || n.pathChild != nil || n.wildChild != nil {
			panic("path not support mix static route")
		}

		if n.children == nil {
			n.children = make(map[string]*node)
		}

		// 判断是否存在
		child, ok := n.children[path]

		if !ok {
			child = &node{path: path}
			n.children[path] = child
		}

		child.handler = handler

		child.addRouterRecursion(paths[1:], handler)
	}

}

func (n *node) findRouter(paths []string, ctx *GCtx) *node {
	// 路径为空
	if len(paths) == 0 {
		return n
	}

	// 获取第一个路径
	path := paths[0]

	// 查找静态路由
	if n.children != nil {
		child, ok := n.children[path]
		if ok {
			return child.findRouter(paths[1:], ctx)
		}
	}

	// 查找正则路由
	if n.regChild != nil {
		if n.reg.MatchString(path) {
			return n.regChild.findRouter(paths[1:], ctx)
		}
	}

	// 查找路径参数路由
	if n.pathChild != nil {
		// 保存路径参数
		ctx.Params[n.pathName] = path

		return n.pathChild.findRouter(paths[1:], ctx)
	}

	// 查找通配符路由
	if n.wildChild != nil {
		return n.wildChild.findRouter(paths[1:], ctx)
	}

	return nil
}

func (n *node) printRouter(i int) {
	if n.handler != nil {
		fmt.Printf("%s%s\n", strings.Repeat(" ", i*4), n.path)
	}

	for _, child := range n.children {
		child.printRouter(i + 1)
	}

	if n.regChild != nil {
		n.regChild.printRouter(i + 1)
	}

	if n.pathChild != nil {
		n.pathChild.printRouter(i + 1)
	}

	if n.wildChild != nil {
		n.wildChild.printRouter(i + 1)
	}
}

func splitPath(path string) []string {
	return strings.Split(path, "/")
}

// Router 路由树
type Router struct {
	// GET root node
	rootGET *node
	// POST root node
	rootPOST *node
	// PUT root node
	rootPUT *node
	// DELETE root node
	rootDELETE *node
}

// GET 添加GET请求路由
func (this *Router) GET(path string, handler HandleFunc) {
	this.addRouter("GET", path, handler)
}

// POST 添加POST请求路由
func (this *Router) POST(path string, handler HandleFunc) {
	this.addRouter("POST", path, handler)
}

// PUT 添加PUT请求路由
func (this *Router) PUT(path string, handler HandleFunc) {
	this.addRouter("PUT", path, handler)
}

// DELETE 添加DELETE请求路由
func (this *Router) DELETE(path string, handler HandleFunc) {
	this.addRouter("DELETE", path, handler)
}

func (this *Router) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	// 获取请求方法
	method := request.Method

	// 获取请求路径
	path := request.URL.Path

	// 获取路由
	var n *node

	switch method {
	case "GET":
		n = this.rootGET
	case "POST":
		n = this.rootPOST
	case "PUT":
		n = this.rootPUT
	case "DELETE":
		n = this.rootDELETE
	default:
		http.Error(writer, "method not support", http.StatusMethodNotAllowed)
		return
	}

	// 路径分割
	paths := splitPath(path)

	ctx := &GCtx{
		Request: request,
		Params:  make(map[string]string),
		writer:  writer,
	}
	// 查找路由
	n = n.findRouter(paths, ctx)

	if n == nil || n.handler == nil {
		http.Error(writer, "404 not found", http.StatusNotFound)
		return
	}

	// 执行路由
	n.handler(ctx)
}

// addRouter 添加路由
func (this *Router) addRouter(method string, path string, handler HandleFunc) {
	switch method {
	case "GET":
		this.rootGET.addRouter(path, handler)
	case "POST":
		this.rootPOST.addRouter(path, handler)
	case "PUT":
		this.rootPUT.addRouter(path, handler)
	case "DELETE":
		this.rootDELETE.addRouter(path, handler)
	default:
		panic("request method not support:" + method)
	}

	return
}

// printRouter 打印路由
func (this *Router) printRouter() {
	fmt.Println("GET:")
	this.rootGET.printRouter(0)
	fmt.Println("POST:")
	this.rootPOST.printRouter(0)
	fmt.Println("PUT:")
	this.rootPUT.printRouter(0)
	fmt.Println("DELETE:")
	this.rootDELETE.printRouter(0)
}

func NewRouter() *Router {
	return &Router{
		rootGET:    &node{},
		rootPOST:   &node{},
		rootPUT:    &node{},
		rootDELETE: &node{},
	}
}

// Middleware generate a http middleware
func (this *Router) Middleware() func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
			this.ServeHTTP(writer, request)
			next.ServeHTTP(writer, request)
		})
	}
}
